package myJs.user.soft.stamp

import com.softwaremill.quicklens._
import myJs.Implicits._
import myJs.Utils.layer
import myJs.api.Api
import myJs.cps._
import myJs.myPkg._
import myJs.myPkg.reactHookForm._
import myJs.tool.Tool
import myJs.tool.Tool.messages
import org.scalajs.dom.{html, window}
import org.scalajs.macrotaskexecutor.MacrotaskExecutor.Implicits._
import shared.Pojo.MetDataKind
import shared.pojo.GroupFileData.GetGroups
import shared.pojo.Pojo
import shared.pojo.Pojo.workflowMission._
import shared.pojo.mission._
import shared.tool.DefaultPickle
import upickle.default._

import scala.collection.immutable.SeqMap
import scala.scalajs.js
import scala.scalajs.js.Dynamic.{global => g}
import scala.scalajs.js.JSON

import japgolly.scalajs.react.vdom.all._
import japgolly.scalajs.react._
import japgolly.scalajs.react.React.Fragment
import japgolly.scalajs.react.util.EffectCatsEffect._
import myJs.myPkg.Hooks._
import cats.effect._
import myJs.Implicits._

/** Created by yz on 3/11/2020
  */
object Cp {

  case class Props(missionName: String) {
    @inline def render: VdomElement = {
      Component(this)
    }
  }

  type SoftData = StampSoftData

  val Component = ScalaFnComponent[Props] { props =>
    val useForm = ReactHookForm.useForm(UseFormOptions(mode = "onChange", resolver = yupResolver(Schema.schema)))
    val (myData, setMyData) = useState(StampSoftData(missionName = props.missionName))
    val (extraData, setExtraData) = useState(ExtraData())

    object FTool {

      def groupFileSelect = (v: String) =>
        {
          setExtraData { x =>
            x.modify(_.fileSelectShow).setTo(false)
          } >>
          setMyData { x =>
            x.modify(_.groupFile).setTo(v)
          }
        }.unsafeRunSync()

      def groupFileSelectShow = {
        if (myData.file.isEmpty) {
          SyncIO{
            useForm.trigger("file")
          }
        } else {
          val newRequest = Pojo.groupFileData.GetAll.Request(fileName = myData.file)
          val newData = extraData
            .modify(_.tabs)
            .setTo(List("group", "example"))
            .modify(_.request)
            .setTo(newRequest)
            .modify(_.fileSelectShow)
            .setTo(true)
            .modify(_.exampleFileName)
            .setTo("group.txt")
            .modify(_.fileSelect)
            .setTo(FTool.groupFileSelect)
          setExtraData(newData)
        }
      }

      def strChange(f: PathLazyModify[SoftData, String]) = (v: String) => {
        setMyData {
          f.setTo(v)
        }
      }

      def vChange[T](f: PathLazyModify[SoftData, T]) = (v: T) => {
        setMyData {
          f.setTo(v)
        }
      }

      def extraDataVChange[T](f: PathLazyModify[ExtraData, T]) = (v: T) => {
        setExtraData {
          f.setTo(v)
        }
      }

      def fileSelect = (v: String) => {
        setExtraData { x =>
          x.modify(_.fileSelectShow).setTo(false)
        } >>
        setMyData { x =>
          x.modify(_.file)
            .setTo(v)
            .modify(_.groupFile)
            .setTo("")
        }
      }.unsafeRunSync()

      def fileSelectShow ={
        val newData = extraData
          .modify(_.tabs)
          .setTo(List(MetDataKind.name, "example"))
          .modify(_.fileSelectShow)
          .setTo(true)
          .modify(_.exampleFileName)
          .setTo("data.txt")
          .modify(_.fileSelect)
          .setTo(FTool.fileSelect)
        setExtraData(newData)
      }

      def inputSelect = (inputE: html.Input) => {
        inputE.select()
      }

      def myRun = () => {
        val layerOptions = LayerOptions.title(Tool.zhInfo).closeBtn(0).skin("layui-layer-molv").btn(js.Array())
        val index = layer.alert(Tool.myElement, layerOptions)
        val request = DefaultPickle.write(myData)
        Api.soft.analysis(request).map { response =>
          layer.close(index)
          if (response.valid) {
            window.location.href = g.jsRoutes.controllers.MissionController.missionManageBefore().url.toString
          } else {
            g.swal("Error", response.message, "error")
          }
        }
        ()
      }

      def getGroups = {
        val request =
          GetGroups.Request(file = myData.file, groupFile = myData.groupFile)
        Api.groupFileData.getGroups(request).map { response =>
          response
        }
      }

      def refreshExtraData = {
        FTool.getGroups.flatMapSync { groups =>
          setExtraData { x =>
            x.modify(_.groups)
              .setTo(groups)
          }
        }
      }

      def formSubmit = useForm.handleSubmit((data: js.Dictionary[js.Any]) => {
        println(JSON.stringify(data))
        FTool.myRun()
      })

    }

    useEffect(
      {
        setMyData { x =>
          val groupVs = Tool.getGroupVs(extraData.groups)
          val defaultGroup = if (groupVs.contains(x.group)) {
            x.group
          } else {
            groupVs.headOption.getOrElse("")
          }
          x.modify(_.group).setTo(defaultGroup)
        }
      },
      List(extraData.groups)
    )

    useEffect(
      {
        val missionId = Tool.getMissionId
        if (missionId.nonBlank) {
          Api.mission.getConfigData(missionId).flatMapSync { response =>
            val responseData = read[SoftData](response)
            val curMyData = responseData.modify(_.missionName).setTo(props.missionName)
            setMyData(curMyData) >> SyncIO{
              useForm.reset(curMyData)
            }

          }
        } else IO {}
      },
      List()
    )

    useEffect(
      {
        if (myData.file.nonBlank && myData.groupFile.nonBlank) {
          FTool.refreshExtraData
        } else IO.unit
      },
      List(myData.file, myData.groupFile)
    )

    val qValueCutoffMap = SeqMap("0.01" -> "0.01", "0.05" -> "0.05")
    val adjustMethodMap = List("bonferroni", "fdr", "none").optionMap
    val groupMap = Tool.getGroupVs(extraData.groups).optionMap
    val isMul = extraData.groups.size > 2

    FormProvider(
      trigger = useForm.trigger _,
      control = useForm.control,
      formState = useForm.formState,
      setValue = useForm.setValue _,
      watch = useForm.watch _,
      getFieldState = useForm.getFieldState _
    )(
      form(
        onSubmit := FTool.formSubmit,
        className := "form-horizontal",
        InputInlineCp
          .Props(
            name = "missionName",
            label = messages("taskName"),
            onChange = FTool.strChange(modifyLens[SoftData](_.missionName)),
            value = myData.missionName,
            onFocus = FTool.inputSelect
          )
          .render,
        FileSelectInlineCp
          .Props(
            fileSelectShow = FTool.fileSelectShow,
            label = messages("dataMatrix"),
            name = "file",
            value = myData.file,
            onChange = FTool.strChange(modifyLens[SoftData](_.file)),
            inputWidth = 4
          )
          .render,
        FileSelectInlineCp
          .Props(
            fileSelectShow = FTool.groupFileSelectShow,
            label = messages("groupFile"),
            name = "groupFile",
            value = myData.groupFile,
            onChange = FTool.strChange(modifyLens[SoftData](_.groupFile)),
            inputWidth = 4
          )
          .render,
        SelectInlineCp
          .Props(
            value = myData.group,
            label = messages("group"),
            name = s"group",
            optionMap = groupMap,
            onChange = FTool.strChange(modifyLens[SoftData](_.group)),
            show = isMul,
            labelWidth = 2,
            inputWidth = 3
          )
          .render,
        FormGroupInlineCp(names = List("qValueCutoff"))(
          SelectInlineNoFormGroupCp
            .Props(
              value = myData.adjustMethod,
              label = "多重校验方法",
              name = "adjustMethod",
              optionMap = adjustMethodMap,
              labelWidth = 2,
              inputWidth = 3,
              onChange = FTool.strChange(modifyLens[SoftData](_.adjustMethod))
            )
            .render,
          InputInlineNoFormGroupCp
            .Props(
              value = myData.qValueCutoff,
              label = "qvalue cutoff",
              name = "qValueCutoff",
              labelWidth = 2,
              inputWidth = 3,
              onChange = FTool.strChange(modifyLens[SoftData](_.qValueCutoff))
            )
            .render
        ),
        FileModalCp
          .Props(
            show = extraData.fileSelectShow,
            showChange = FTool.extraDataVChange(modifyLens[ExtraData](_.fileSelectShow)),
            softKind = myData.kind,
            exampleFileName = extraData.exampleFileName,
            fileSelect = (v: String) => SyncIO { extraData.fileSelect(v) },
            request = extraData.request,
            tabs = extraData.tabs
          )
          .render,
        div(
          className := "form-group form-horizontal",
          marginTop := 0.px,
          div(
            className := "actions col-sm-offset-2 col-sm-2",
            button(`type` := "submit", className := "btn btn-primary", width := "90%", messages("run"))
          )
        )
      )
    )

  }

}
